
                /*********************************************
                **                                          **
                **                                          **
                **                cs.1.C                    **
                **                                          **
                **                                          **
                *********************************************/
                /*********************************************
                **                                          **
                **         Author Jean-Marc Adamo           **
                **       Copyright (C) 1997-2008 JMA        **
                *********************************************/

/*
** testsyncSR1.C
** testing send, recv and Sdf::alt through ChanR
** Needs at least 3 processes
*/

#include "arch.h"

//user program
Global_id gid1;
Global_id gid2;
Global_id gid3;
Global_id gid4;
Coll_id cid;

void init_gid(int, char **){
   gid1.set();
   gid2.set();
   gid3.set();
   gid4.set();
   cid.set();
   fprintf(Sdf::trace, "node%d: gid1.tag=%d, gid2.tag=%d, gid3.tag=%d, gid4.tag=%d, cid.tag=%d\n",
           Sdf::PROC_ID, gid1.get(), gid2.get(), gid3.get(), gid4.get(), cid.get());
   fflush(Sdf::trace);
}

ChanR *chan;
ChanR *chan1;
ChanR **chan2;


class Sender: public S_Thread{

   public:

        Sender()
        : S_Thread((Smf0_ptr)&Sender::body){}


        void body(){


         fprintf(Sdf::trace, "node %d, in proc %d before for loop\n",
                 Sdf::PROC_ID, 0);

         for(int j=0; j<2; j++){

           chan->send();

           fprintf(Sdf::trace, "node %d, in proc %d after send chan, j = %d\n",
                   Sdf::PROC_ID, 0, j);
           fflush(Sdf::trace);
         }

         chan2[0]->send();

         fprintf(Sdf::trace, "node %d, in proc %d after send chan2[0].0\n",
                 Sdf::PROC_ID, 0);
         fflush(Sdf::trace);

         chan2[1]->send();

         fprintf(Sdf::trace, "node %d, in proc %d after send chan2[1].0\n",
                 Sdf::PROC_ID, 0);
         fflush(Sdf::trace);

         chan2[0]->send();

         fprintf(Sdf::trace, "node %d, in proc %d after send chan2[0].1\n",
                 Sdf::PROC_ID, 0);
         fflush(Sdf::trace);

         chan2[1]->send();

         fprintf(Sdf::trace, "node %d, in proc %d after send chan2[1].1\n",
                 Sdf::PROC_ID, 0);


         fprintf(Sdf::trace, "node %d, in proc %d sender ends up\n",
                 Sdf::PROC_ID, 0);
         fflush(Sdf::trace);
    }

};


class Receiver: public S_Thread{

   public:

        Receiver()
                : S_Thread((Smf0_ptr)&Receiver::body){}

        void body(){

           fprintf(Sdf::trace, "node %d, in proc %d before for loop\n",
                   Sdf::PROC_ID, 1);
           fflush(Sdf::trace);

           for(int j=0; j<2; j++){

             chan->recv();

             fprintf(Sdf::trace, "node %d, in proc %d after recv chan, j = %d\n",
                     Sdf::PROC_ID, 1, j);
           }

           chan2[0]->recv();

           fprintf(Sdf::trace, "node %d, in proc %d after recv chan2[0]\n", 
                   Sdf::PROC_ID, 1);
           fflush(Sdf::trace);

           chan2[1]->recv();

           fprintf(Sdf::trace, "node %d, in proc %d after recv chan2[1]\n", 
                   Sdf::PROC_ID, 1);
           fflush(Sdf::trace);

           Alts *alt_table[2];
           alt_table[0] =  new AltR(chan2[0], 
                                    this,
                                    (Smf2_ptr)&Receiver::alt_body,
                                    0);

           alt_table[1] =  new AltR(chan2[1], 
                                    this,
                                    (Smf2_ptr)&Receiver::alt_body,
                                    0);

           AltCtrl *alt_ctrl = new AltCtrl(2, alt_table);

           for(int i = 0; i< 2; i++){
              Sdf::alt(alt_ctrl);
           }

           delete alt_table[0], delete alt_table[1];
           delete alt_ctrl;

           fprintf(Sdf::trace, "node %d, in proc %d receiver ends up\n",
                   Sdf::PROC_ID, 1);
           fflush(Sdf::trace);

        }



        void alt_body(int rank, void *arg_ptr){
             fprintf(Sdf::trace, "node %d, in proc %d in alt_body.%d\n",
                     Sdf::PROC_ID, 1, rank);
             fflush(Sdf::trace);
        }
};

class Root_proc: public Thread{

   public:
        Root_proc()
                : Thread((Tmf0_ptr)&Root_proc::body){}

        void body(){

            fprintf(Sdf::trace, "node %d, in Root_proc::body1\n", Sdf::PROC_ID);
            fflush(Sdf::trace);

            chan = new ChanR(gid1, (Sdf::PROC_ID+1)%Sdf::PROC_NB);
            chan1 = new ChanR(gid2, (Sdf::PROC_ID+1)%Sdf::PROC_NB);

            chan2 = new ChanR *[Sdf::PROC_NB-1];
            chan2[0] = new ChanR(gid3, (Sdf::PROC_ID+1)%Sdf::PROC_NB);
            chan2[1] = new ChanR(gid4, (Sdf::PROC_ID+2)%Sdf::PROC_NB);

            Sdf::barrier(cid);
                //synchronizes chan construction(no longer
                //necessary starting from version 5)

            Sender * sender = new Sender;
            Receiver * receiver = new Receiver;

            fprintf(Sdf::trace, "node %d, chan = %d, chan1 = %d, chan2[0] = %d, chan2[1] = %d, sender = %d, receiver = %d\n",
            Sdf::PROC_ID, chan, chan1, chan2[0], chan2[1], sender, receiver);

            fprintf(Sdf::trace, "node %d, in Root_proc::body2\n", Sdf::PROC_ID);
            fflush(Sdf::trace);

            S_Thread *proc_tabl[2] = {sender, receiver};
            int pri[2] = {1, 1};
            par(2, proc_tabl, pri);

            fprintf(Sdf::trace,"node %d, in Root_proc::body3\n", Sdf::PROC_ID);
            fflush(Sdf::trace);

            Sdf::barrier(cid);
                 //synchronizes chan destruction
            delete []chan2;
            delete chan1;
            delete chan;
            delete sender;
            delete receiver;
    }
};

//end of user program


MAIN(Root_proc, init_gid, Sdf::empty, Sdf::empty)


